package com.lagou.edu.factory;


import com.lagou.edu.annotation.Autowired;
import com.lagou.edu.annotation.Service;
import com.lagou.edu.annotation.Transactional;
import org.reflections.Reflections;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 用于解析注解
 */
public class AnnotationBeanFactory {
    private static Map<String,Object> map = new HashMap<String,Object>(); // 用于存储

    static {
        try {
                // Reflections第三方反射框架   扫描包获取元数据
                Reflections reflections = new Reflections("com.lagou.edu");
                Set<Class<?>> classes = reflections.getTypesAnnotatedWith(Service.class);//获取注解标记的类
                 //遍历集合
                for (Class<?> aClass : classes) {
                    // 获取实例化对象
                    Object o = aClass.newInstance();
                    Service annotation = aClass.getAnnotation(Service.class);//获取注解对象
                    // 判断注解是否有自定义对象的id   @Service(value = "accountDao")
                    if(annotation.value().isEmpty()){// 如果没有写value值这获取注解标记的类名
                        // 获取类名存入map key 获取具体对象存入map value
                        String name = aClass.getName();//getName()获取的是权限定类名
                        String[] split = name.split("\\.");
                        String name1 = split[split.length-1];
                        String toname = (new StringBuilder()).append(Character.toLowerCase(name1.charAt(0))).append(name1.substring(1)).toString();
                        map.put(toname,o);

                    }else{//直接获取value值存入map key中
                        map.put(annotation.value(),o);
                    }

                }
                // 维护对象之间的关系    得到@Autowired修饰的属性遍历 通过反射获取具体值并注入
                for(Map.Entry<String,Object> m:map.entrySet()) {
                    Object value = m.getValue();//获取map中的value
                    Class<?> aClass = value.getClass(); // 实例化对象
                    // 获取类中的所有属性
                    Field[] declaredFields = aClass.getDeclaredFields();
                    for (Field field : declaredFields) {
                        //判断是否使用@Autowired注解     @Autowired 默认为true
                        if (field.isAnnotationPresent(Autowired.class) && field.getAnnotation(Autowired.class).value()) {
                            String[] names = field.getType().getName().split("\\.");// field.getType()获取类型  .getName()获取权限定名
                            String name = names[names.length - 1];
                            String toname = (new StringBuilder()).append(Character.toLowerCase(name.charAt(0))).append(name.substring(1)).toString();
                            Method[] methods = aClass.getMethods();// 获取所有方法
                            for (int i = 0; i < methods.length; i++) {
                                Method method = methods[i];
                                if (method.getName().equalsIgnoreCase("set" + name)) {//如果set方法则注入
                                    method.invoke(value, map.get(toname)); //给形参赋值
                                }
                            }
                        }
                    }
                    // 判断该类是否@Transactional 如果是则代理改对象
                    if(aClass.isAnnotationPresent(Transactional.class)){
                        //获取代理工厂
                        ProxyFactory proxyFactory = (ProxyFactory)AnnotationBeanFactory.getBean("proxyFactory");
                        //获取注解类所有实现接口
                        Class<?>[] interfaces = aClass.getInterfaces();
                        if(interfaces != null &interfaces.length>0){//如果有实现的接口则使用jdk动态代理
                            value = proxyFactory.getProxy(value); //将map中的value作为参数传入,并返回代理后的对象
                        }else{
                            value = proxyFactory.getCjlbProxy(value);
                        }
                    }
                    // 将处理后的object重新放入map中
                    map.put(m.getKey(),value);
                }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
    // 提供获取bean方法
    public static Object getBean(String id ){
        return map.get(id);
    }
}
